/*!
* @file BoundBox3D.h
* @brief 三维包围盒
* @date 2024/9/12
*/
#pragma once

#include "Vector3D.h"
#include "BoundBox2D.h"

namespace data
{
class Matrix4d;
/*!
* @brief 三维包围盒
*/
template<class float_type>
class BoundBox3
{
public:
    using traits_type = std::numeric_limits<float_type>;
    using vector_type = Vector3<float_type>;

    /*!
    * @brief 包围盒构造
    */
    BoundBox3() { MakeEmpty(); }
    BoundBox3(const BoundBox3& bbox) = default;
    BoundBox3(BoundBox3&& bbox) noexcept = default;
    BoundBox3(float_type x1, float_type y1, float_type z1, float_type x2, float_type y2, float_type z2) 
        : _minX(x1), _minY(y1), _minZ(z1), _maxX(x2), _maxY(y2), _maxZ(z2) {}
    BoundBox3(const vector_type* points, std::size_t cnt);
    BoundBox3(const vector_type& point, float_type distance);
    ~BoundBox3() = default;

    /*!
    * @brief 包围盒运算
    */
    BoundBox3& operator=(const BoundBox3& bbox) = default;
    BoundBox3& operator=(BoundBox3&& bbox) noexcept = default;

    void MakeEmpty();
    bool IsValid() const;

    vector_type Minimum() const;
    vector_type Maximum() const;
    vector_type Center() const;
    void GetCorners(vector_type corners[8]) const;

    float_type LengthX() const;
    float_type LengthY() const;
    float_type LengthZ() const;
    float_type Diagonal() const;
    float_type Volume() const;

    void Add(const vector_type& vec);
    bool Contains(const vector_type& vec) const;
    bool Intersect(const vector_type& position, const vector_type& dir) const;
    void Add(const BoundBox3& bbox);
    bool Contains(const BoundBox3& bbox) const;
    bool Intersect(const BoundBox3& bbox) const;
    bool IsEqual(const BoundBox3& bbox, float_type tol) const;

    BoundBox3 Intersected(const BoundBox3& bbox) const;
    BoundBox3 United(const BoundBox3& bbox) const;

    void Enlarge(float_type len);
    void Shrink(float_type len);
    void Move(const vector_type& vec);
    void Scale(const vector_type& scales);
    void Transform(const Matrix4d& mat);
    BoundBox3 Transformed(const Matrix4d& mat) const;

    /*!
    * @brief 文本信息输出
    */
    friend std::ostream& operator<< (std::ostream& stream, const BoundBox3& b)
    {
        return stream << "{ minX: " << b._minX << ", _minY: " << b._minY << ", _minZ: " << b._minZ 
            << " maxX: " << b._maxX << ", _maxY: " << b._maxY << " maxZ: " << b._maxZ << " }";
    }

private:
    /// 成员
    float_type _minX, _minY, _minZ, _maxX, _maxY, _maxZ;
};

using BoundBox3f = BoundBox3<float>;
using BoundBox3d = BoundBox3<double>;

}  // namespace data
